/*
 * Copyright 2017 Baiyyy
 * @(#)PsZcdHzService.java
 */

package com.byyy.ccts.modules.cc.service.impl;

import com.baomidou.mybatisplus.mapper.Wrapper;
import com.byyy.ccts.core.common.service.impl.CommonServiceImpl;
import com.byyy.ccts.core.query.data.Page;
import com.byyy.ccts.core.query.data.PageImpl;
import com.byyy.ccts.core.query.data.Pageable;
import com.byyy.ccts.core.query.data.Queryable;
import com.byyy.ccts.core.query.parse.QueryToWrapper;
import com.byyy.ccts.core.utils.BeanUtils;
import com.byyy.ccts.core.utils.StringUtils;
import com.byyy.ccts.modules.cc.entity.ccts.*;
import com.byyy.ccts.modules.cc.enums.PsStateEnum;
import com.byyy.ccts.modules.cc.enums.WhetherOrNotEnum;
import com.byyy.ccts.modules.cc.enums.WorkingStateEnum;
import com.byyy.ccts.modules.cc.mapper.*;
import com.byyy.ccts.modules.cc.service.IPsZcdMxService;
import com.byyy.ccts.modules.cc.service.IPsZcdService;
import com.byyy.ccts.modules.common.enums.ExceptionEnum;
import com.byyy.ccts.modules.common.exception.BusinessAjaxException;
import com.byyy.ccts.modules.sys.entity.Log;
import com.byyy.ccts.modules.sys.entity.User;
import com.byyy.ccts.modules.sys.service.IParamService;
import com.byyy.ccts.modules.sys.utils.UserUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;

/**
 * Created by DELL on 2018-6-14.
 */
@Transactional
@Service("psZcdMxService")
public class PsZcdMxService extends CommonServiceImpl<PsZcdMxMapper, PsZcdMx> implements IPsZcdMxService {

    @Autowired
    private IPsZcdService psZcdService;

    @Autowired
    private IParamService paramService;

    @Autowired
    private PsZcdMxMapper psZcdMxMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private CouvenseMapper couvenseMapper;

    @Autowired
    private ChillCarMapper chillCarMapper;

    @Autowired
    private PsZcdMapper psZcdMapper;

    @Autowired
    private HumitureMapper humitureMapper;

    @Autowired
    private DeviceWarningLogMapper deviceWarningLogMapper;

    /**
     * 装车单关联操作
     * 1.根据流水号等进行关联操作
     * 2.判断设备是否已关联其他单据
     * 3.更新装车单汇总状态
     * 4.更新采集设备以及保温箱状态
     * @return
     */
    @Override
    public String relation(List<TsRelation> relations) {
        // 变量定义
        StringBuilder sb = new StringBuilder();
        String repeatNo = null;
        List<PsZcdMx> zcdMxList = null;
        List<String> barcodes = new ArrayList<>();
        List<String> cjIds = new ArrayList<>();
        List<String> lcSns = new ArrayList<>();
        PsZcdHz psZcdHz = null;
        PsZcdMx psZcdMx = null;

        boolean existElectricWarning = false;
        List<TsRelation> electricWarningList = new ArrayList<>();
        // 分别获取流水号，冷藏箱，采集设备
        for (TsRelation temp : relations) {
            barcodes.add(temp.getLiushBarcode());
            if (!cjIds.contains(temp.getCjId())) {
                cjIds.add(temp.getCjId());
            }
            if (!lcSns.contains(temp.getLcSn())) {
                lcSns.add(temp.getLcSn());
            }

            // 查找是否存在电量预警设备进行了关联
            if (temp.getElectricWarning()) {
                // 去重
                for (TsRelation tempElectricWarning : electricWarningList) {
                    if (tempElectricWarning.getCjId().equals(temp.getCjId())) {
                        existElectricWarning = true;
                        break;
                    }
                }
                if (!existElectricWarning) {
                    electricWarningList.add(temp);
                }
            }
        }

        zcdMxList = this.psZcdMxMapper.selectByBarcodes(barcodes);
        repeatNo = zcdMxList.get(0).getZhuangcdNo();

        // 获取汇总信息,改变装车单状态：1：已关联
        psZcdHz = this.psZcdService.selectById(zcdMxList.get(0).getZhuangcdNo());
        psZcdHz.setState(PsStateEnum.已关联.getValue());

        for (PsZcdMx tempMx : zcdMxList) {
            tempMx.setCaozStaff(UserUtils.getUser().getId());
            // 判断是否存在尚未作废的重装单据
            if (!repeatNo.equals(tempMx.getZhuangcdNo())) {
                sb.append("装车单").append(repeatNo).append("与").append(tempMx.getZhuangcdNo()).append("中存在重装单据，请先作废以前的单据！");
                return sb.toString();
            }
            for (TsRelation temp : relations) {
                if (tempMx.getLiushBarcode().equals(temp.getLiushBarcode())) {
                    tempMx.setSbSn(temp.getCjId());
                    tempMx.setBoxSn(temp.getLcSn());
                    tempMx.setCarFlag(WhetherOrNotEnum.否.getValue());
                    tempMx.setPointone("");
                    tempMx.setPointtwo("");
                    break;
                }
            }
        }

        // 目前在选择设备和保温箱页面已经做过验证，其次在微信端的装箱关联时也有了验证，所以目前该验证是不需要的
        if (isBindingOthZcdMx(psZcdHz.getZhuangcdNo(), cjIds, lcSns)) {
            sb.append("每台设备或者保温箱只能关联到一个装车单下，请确认后重新关联");
            return sb.toString();
        }

        // 判断是否存在已关联设备，如果存在，则清空原状态
        this.deviceMapper.clearStateByBarcodes(barcodes, WorkingStateEnum.未关联.getValue());
        this.couvenseMapper.clearStateByBarcodes(barcodes, WorkingStateEnum.未关联.getValue());
        this.chillCarMapper.clearStateByBarcodes(barcodes, WorkingStateEnum.未关联.getValue());

        // 更新汇总，明细，设备信息
        this.updateBatchById(zcdMxList);
        this.psZcdService.updateById(psZcdHz);
        this.deviceMapper.updateWorkingByIds(cjIds, WorkingStateEnum.已关联.getValue());
        this.couvenseMapper.updateWorkingByIds(lcSns, WorkingStateEnum.已关联.getValue());

        // 电量预警设备关联记录
        this.electricWarningRecord(electricWarningList, zcdMxList);

        return sb.toString();
    }

    /**
     * 装车单明细简单查询-供配送交接使用
     * @param zcdNo
     * @return
     */
    @Override
    public List<PsZcdMx> selectSimpleListByZcdNo(String zcdNo) {
        List<PsZcdMx> zcdMxList = psZcdMxMapper.selectSimpleListByZcdNo(zcdNo);
        return zcdMxList;
    }

    /**
     * 根据装车单列表查询装车单明细信息
     * @param zcdNos
     * @return
     */
    @Override
    public List<PsZcdMx> selectByZcdNos(List<String> zcdNos) {
        return this.psZcdMxMapper.selectByZcdNos(zcdNos);
    }

    /**
     * 更新商品存储温度
     * @param zcdMxList
     * @return
     */
    @Override
    public String updProdsTemp(List<PsZcdMx> zcdMxList) {
        for (PsZcdMx temp : zcdMxList) {
            this.baseMapper.updShangpCondition(temp);
        }
        return null;
    }

    /**
     * 更新商品第三方温度
     * @param zcdMxList
     * @return
     */
    @Override
    public String updProdsTempDSF(List<PsZcdMx> zcdMxList) {
        for (PsZcdMx temp : zcdMxList) {
            this.baseMapper.updDSFTemp(temp);
        }
        return null;
    }

    @Override
    public Page<PsZcdMx> zcdMxList(Queryable queryable, Wrapper<PsZcdMx> wrapper) {
        QueryToWrapper<PsZcdMx> queryToWrapper = new QueryToWrapper<>();
        queryToWrapper.parseCondition(wrapper, queryable);
        // 排序问题
        queryToWrapper.parseSort(wrapper, queryable);
        Pageable pageable = queryable.getPageable();
        com.baomidou.mybatisplus.plugins.Page<PsZcdMx> page = new com.baomidou.mybatisplus.plugins.Page<PsZcdMx>(
                pageable.getPageNumber(), pageable.getPageSize());
        com.baomidou.mybatisplus.plugins.Page<PsZcdMx> content = zcdMxListPage(page, wrapper);
        return new PageImpl<PsZcdMx>(content.getRecords(), queryable.getPageable(), content.getTotal());
    }

    @Override
    public com.baomidou.mybatisplus.plugins.Page<PsZcdMx> zcdMxListPage(com.baomidou.mybatisplus.plugins.Page<PsZcdMx> page, Wrapper<PsZcdMx> wrapper) {
        page.setRecords(baseMapper.zcdMxListPage(page, wrapper));
        return page;
    }

    /**
     * 装车单拆分
     * @param zhuangcdId
     * @param number
     * @return
     */
    @Override
    public String zcdSplit(String zhuangcdId, int number){
        PsZcdMx psZcdMx =  this.selectById(zhuangcdId);

        int shijJs = psZcdMx.getShijJs();
        String liushBarcode = psZcdMx.getLiushBarcode();
        List<PsZcdMx> psZcdMxListNew = new ArrayList<>();
        int jsNew = shijJs / number;
        int jsLast = jsNew + shijJs % number;
        PsZcdMx psZcdMxNew = null;

        try {
            for (int i = 1; i <= number; i++) {
                psZcdMxNew = new PsZcdMx();
                PropertyUtils.copyProperties(psZcdMxNew, psZcdMx);
                psZcdMxNew.setZhuangcdId(zhuangcdId + '_' + i);
                psZcdMxNew.setLiushBarcode(liushBarcode + '_' + i);
                if (i == number) {
                    psZcdMxNew.setShijJs(jsLast);
                    psZcdMxNew.setShijNum(jsLast * psZcdMxNew.getBaozNum());
                } else {
                    psZcdMxNew.setShijJs(jsNew);
                    psZcdMxNew.setShijNum(jsNew * psZcdMxNew.getBaozNum());
                }
                psZcdMxListNew.add(psZcdMxNew);
            }

        } catch (Exception e) {
            throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX, "装车单拆分错误");
        }
        this.insertBatch(psZcdMxListNew);
        this.psZcdMxMapper.deleteById(zhuangcdId);
        return  null;
    }

    /**
     * API-关联操作
     * @param relations
     * @param isWhole
     * @return
     */
    @Override
    public String relationForApi(List<TsRelation> relations, boolean isWhole) {
        // 定义变量
        StringBuilder sb = new StringBuilder();
        List<PsZcdMx> zcdMxList = null;
        TsRelation relation = null;
        List<TsRelation> tempRealations = null;
        Timestamp timestamp = null;

        // 整单关联，查出整单下所有的流水号进行关联操作
        if(isWhole) {
            tempRealations = new ArrayList<>();

            // 查出单据下的所有流水号进行关联操作
            for (TsRelation temp : relations) {
                zcdMxList = this.selectByZcdNos(Arrays.asList(temp.getLiushBarcode()));
                if (zcdMxList == null || zcdMxList.size() < 1) {
                    sb.append(temp.getLiushBarcode()).append(";");
                    continue;
                }

                // 关联关系暂存
                for (PsZcdMx tempMx : zcdMxList) {
                    relation = new TsRelation();
                    relation.setCjId(temp.getCjId());
                    relation.setLcSn(temp.getLcSn());
                    relation.setLiushBarcode(tempMx.getLiushBarcode());
                    tempRealations.add(relation);
                }
            }
            if (StringUtils.isNotEmpty(sb.toString())) {
                sb.append("以上装车单未查询到数据，请确认后重新关联");
                return sb.toString();
            }
            // 插入
            if (tempRealations != null && tempRealations.size() > 0) {
                sb.append(this.relationZcdForApi(tempRealations));
            }
            return sb.toString();
        }

        // 非整单关联，直接通过流水号进行关联操作
        sb.append(this.relationZcdForApi(relations));
        return sb.toString();
    }

    /**
     * API-获取设备当前温度
     * @param zcdNo
     * @return
     */
    @Override
    public Map<String, Object> deviceCurTempForApi(String zcdNo) {
        Map<String, Object> ret = new HashMap<>();
        String msg = null;
        boolean isCar = false;
        PsZcdHz psZcdHz = null;
        List<PsZcdMx> psZcdMxList = null;
        StringBuilder sb = new StringBuilder();
        List<String> cjIdList = new ArrayList<>();

        // 查看装车单
        psZcdHz = this.psZcdService.selectById(zcdNo);
        if (psZcdHz == null) {
            ret.put("msg", "未查询到装车单数据");
            return ret;
        }

        // 判断装车单状态
        msg = this.psZcdService.psStateCompare(psZcdHz, PsStateEnum.已关联.getValue());
        if (StringUtils.isNotEmpty(msg)) {
            ret.put("msg", msg);
            return ret;
        }

        // 根据装车单号查询关联设备信息
        psZcdMxList = this.selectByZcdNos(Arrays.asList(zcdNo));
        if (psZcdMxList == null || psZcdMxList.size() < 1) {
            ret.put("msg", "未查询到装车单明细数据");
            return ret;
        }
        // 判断单据是否关联的冷藏车
        isCar = WhetherOrNotEnum.否.getValue().equals(psZcdMxList.get(0).getCarFlag()) ? false: true;

        // 判断是否做了装箱关联，以及商品是否存在未维护温度的情况
        for (PsZcdMx temp : psZcdMxList) {
            if (!isCar && (StringUtils.isEmpty(temp.getBoxSn())
                    || StringUtils.isEmpty(temp.getSbSn()))) {
                ret.put("msg", sb.append("装车单内存在未关联的设备或者保温箱，请确认后重新发车！").toString());
                return ret;
            }
            // 判断是否存在存储温度为空的商品
            if (temp.getWendMin() == null || temp.getWendMax() == null) {
                if (sb.indexOf(temp.getShangpNo()) < 0) {
                    sb.append(temp.getShangpNo()).append(";");
                }
            }
        }
        if (StringUtils.isNotEmpty(sb.toString())) {
            ret.put("msg", "上述商品未维护存储温度");
            return ret;
        }

        // 如果是冷藏车关联，那么整个冷藏车的温度采集设备都是一样的，就不用循环取值了
        if (isCar) {
            cjIdList.add(psZcdMxList.get(0).getPointone());
            cjIdList.add(psZcdMxList.get(0).getPointtwo());
        }
        else {
            for (PsZcdMx temp : psZcdMxList) {
                cjIdList.add(temp.getSbSn());
            }
        }

        // 查询设备温度
        List<TADevice> deviceList = this.deviceMapper.selectDeviceInfo(cjIdList);
        if (deviceList == null || deviceList.size() < 1) {
            ret.put("msg", "未查询到设备温度信息");
            return ret;
        }
        for (TADevice device : deviceList) {
            if (StringUtils.isEmpty(device.getTemperature())) {
                ret.put("msg", sb.append(device.getId()).append("未查询到温度信息").toString());
                return ret;
            }
        }

        ret.put("data", deviceList);

        return ret;
    }

    /**
     * 根据设备ID查询是否是在途运送的数据，查询单据信息
     * @param sn
     * @return
     */
    @Override
    public PsZcdMx selectMxOnTheWayBySN(String sn) {
        return this.baseMapper.selectMxOnTheWayBySN(sn);
    }

    /**
     * API-拆分装车单
     * 1.首先判断有没有满足大于该流水号拆分件数的明细，没有就提示“该流水号没有可以拆分的件数”
     * @param cjId
     * @param lcSn
     * @param liushBarcode
     * @param splitNumber
     * @return
     */
    @Override
    public String zcdSplitForApi(String cjId, String lcSn, String liushBarcode, int splitNumber) {
        StringBuilder stringBuilder = new StringBuilder();
        PsZcdMx zcdMxOld = null;
        PsZcdMx zcdMxNew = null;
        List<PsZcdMx> psZcdMxList = null;
        int index = 0;
        String zcdId = null;
        String[] zcdIds = null;
        // 根据流水号查找明细
        psZcdMxList = this.baseMapper.selectByBarcodes(Arrays.asList(liushBarcode));
        if (psZcdMxList == null || psZcdMxList.size() < 1) {
            return stringBuilder.append("未能根据流水号").append(liushBarcode).append("查找到单据信息,请确认是否已管理或已发车").toString();
        }

        // 判断是否有满足可以拆分的明细
        for (PsZcdMx temp : psZcdMxList) {
            if (temp.getShijJs() > splitNumber) {
                zcdMxOld = temp;
                break;
            }
        }
        if (zcdMxOld == null) {
            return stringBuilder.append("未能找到该流水号").append(liushBarcode).append("内存在符合拆分件数").append(splitNumber).append("的明细").toString();
        }

        try {
            // 有符合拆分件数的，拆分出一条新的明细记录，同时修改旧的记录
            zcdMxNew = (PsZcdMx) BeanUtils.cloneBean(zcdMxOld);
            // 根据装车单明细号找到最大的index，继续往下累加
            psZcdMxList = this.baseMapper.selectZcdMxLikeId(stringBuilder.append(zcdMxNew.getZhuangcdId()).append("%").toString());
            // TODO 同一装车单ID下，即拆分过的装车单是否需要判断重复
            zcdId = psZcdMxList.get(0).getZhuangcdId();
            // 如果装车单明细内匹配到两个_，说明已经被拆分过，这时候就找他的最大index转int后加1，如果匹配到一个，说明还未被拆分，此时index从1开始计数
            int cnt = StringUtils.countMatches(zcdId, "_");
            zcdIds = StringUtils.split(zcdId, "_");
            stringBuilder.delete(0, stringBuilder.length());
            if (cnt > 1) {
                index = Integer.valueOf(zcdIds[2]) + 1;
                zcdId = stringBuilder.append(zcdIds[0]).append("_").append(zcdIds[1]).append("_").append(index).toString();
            }
            else {
                index = 1;
                zcdId = stringBuilder.append(zcdId).append("_").append(index).toString();
            }
            zcdMxNew.setShijJs(splitNumber);
            zcdMxNew.setShijNum(splitNumber * zcdMxNew.getBaozNum());
            zcdMxNew.setZhuangcdId(zcdId);
            zcdMxNew.setLiushBarcode(zcdMxNew.getLiushBarcode() + "_" + index);

            // 旧的装车单修改件数后保存
            zcdMxOld.setShijJs(zcdMxOld.getShijJs() - splitNumber);
            zcdMxOld.setShijNum(zcdMxOld.getShijNum() - splitNumber * zcdMxNew.getBaozNum());

            this.insert(zcdMxNew);
            this.updateById(zcdMxOld);

        } catch (Exception e) {
            throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX, "装车单拆分错误");
        }

        // 关联
        TsRelation relation = new TsRelation();
        relation.setLiushBarcode(zcdMxNew.getLiushBarcode());
        relation.setCjId(cjId);
        relation.setLcSn(lcSn);

        return this.relationZcdForApi(Arrays.asList(relation));
    }

    @Override
    public List<PsZcdMx> selectByBarcodes(List<String> barcodes) {
        return this.baseMapper.selectByBarcodes(barcodes);
    }

    /**
     * 根据设备ID查询是否是在途运送的数据，查询单据信息
     * @param car
     * @return
     */
    @Override
    public PsZcdMx selectMxOnTheWayByCar(String car) {
        return this.baseMapper.selectMxOnTheWayByCar(car);
    }

    /**
     * 根据装车单号获取明细信息（冷藏车专用）
     * @param zcdNos
     * @return
     */
    @Override
    public List<PsZcdMx> selectCarMxByZcdNos(List<String> zcdNos) {
        return this.psZcdMxMapper.selectCarMxByZcdNos(zcdNos);
    }

    /**
     * 判断是否绑定了其他已激活或者已关联的装车单
     * @param zcdNo
     * @param cjIds
     * @param lcSns
     * @return
     */
    private boolean isBindingOthZcdMx(String zcdNo, List<String> cjIds, List<String> lcSns) {
        List<PsZcdMx> zcdMxList = this.psZcdMxMapper.isBindingOthZcdMx(zcdNo, cjIds, lcSns);
        if (zcdMxList == null || zcdMxList.size() < 1) {
            return false;
        }
        return true;
    }

    /**
     * 采集设备、保温箱No转Id
     * @param relations
     * @return
     */
    private List<TsRelation> convertNo2Id(List<TsRelation> relations) {
        List<PsZcdHz> psZcdHzList = this.psZcdMapper.selectByBarcodes(Arrays.asList(relations.get(0).getLiushBarcode()));
        if (psZcdHzList == null || psZcdHzList.size() < 1) {
            return relations;
        }

        String cangku = psZcdHzList.get(0).getCangku();
        TADevice device = null;
        TACouvense couvense = null;
        for (TsRelation relation : relations) {
            device = this.deviceMapper.queryByNoAndCangku(Arrays.asList(relation.getCjId()), cangku).get(0);
            couvense = this.couvenseMapper.queryByNoAndCangku(Arrays.asList(relation.getLcSn()), cangku).get(0);
            relation.setCjId(device.getId());
            relation.setLcSn(couvense.getId());
        }

        return relations;
    }

    /**
     * API进行关联操作
     * @param relations
     * @return
     */
    private String relationZcdForApi(List<TsRelation> relations) {
        // 定义变量
        StringBuilder sb = new StringBuilder();
        String repeatNo = null;
        List<PsZcdHz> psZcdHzList = null;
        List<PsZcdMx> psZcdMxList = null;
        List<PsZcdMx> repeatMxList = null;
        List<PsZcdMx> fullMxList = null;
        List<String> liushBarcodeList = new ArrayList<>();
        List<String> cjIds = new ArrayList<>();
        List<String> lcSns = new ArrayList<>();
        Map<String, String> repeatMap = new HashMap<>();
        List<TADevice> deviceList = null;
        List<TACouvense> couvenseList = null;
        User user = UserUtils.getUser();

        relations = this.convertNo2Id(relations);
        // 生成流水号列表
        for (TsRelation temp : relations) {
            if (!liushBarcodeList.contains(temp.getLiushBarcode())) {
                liushBarcodeList.add(temp.getLiushBarcode());
            }
        }

        // 首先查看是否存在装车单汇总和明细数据
        psZcdHzList = this.psZcdMapper.selectByBarcodes(liushBarcodeList);
        if (psZcdHzList == null || psZcdHzList.size() < 1) {
            sb.append("未查询到对应的装车单数据");
            return sb.toString();
        }
        psZcdMxList = this.psZcdMxMapper.selectByBarcodes(liushBarcodeList);
        if (psZcdMxList == null || psZcdMxList.size() < 1) {
            sb.append("未查询到对应的装车单明细数据");
            return sb.toString();
        }

        // 判断是否所有的流水号都能找到对应的装车单明细
        boolean exist = false;
        boolean existElectricWarning = false;
        List<TsRelation> electricWarningList = new ArrayList<>();
        for (TsRelation tempRelation : relations) {
            exist = false;
            existElectricWarning = false;
            for (PsZcdMx temp : psZcdMxList) {
                if (tempRelation.getLiushBarcode().equals(temp.getLiushBarcode())) {
                    exist = true;
                    break;
                }
            }
            if (!exist) {
                sb.append(tempRelation.getLiushBarcode()).append(";");
            }
            // 查找是否存在电量预警设备进行了关联
            if (tempRelation.getElectricWarning()) {
                // 去重
                for (TsRelation tempElectricWarning : electricWarningList) {
                    if (tempElectricWarning.getCjId().equals(tempRelation.getCjId())) {
                        existElectricWarning = true;
                        break;
                    }
                }
                if (!existElectricWarning) {
                    electricWarningList.add(tempRelation);
                }
            }
        }
        if (!StringUtils.isEmpty(sb.toString())) {
            sb.append("以上流水号未查询到数据，请确认后重新关联");
            return sb.toString();
        }

        // 创建关联关系
        repeatNo = psZcdMxList.get(0).getZhuangcdNo();
        for (PsZcdMx temp : psZcdMxList) {
            for (TsRelation tempRelation : relations) {
                if (temp.getLiushBarcode().equals(tempRelation.getLiushBarcode())) {
                    temp.setSbSn(tempRelation.getCjId());
                    temp.setBoxSn(tempRelation.getLcSn());
                    cjIds.add(temp.getSbSn());
                    lcSns.add(temp.getBoxSn());
                    break;
                }
            }

            // 判断是否存在尚未作废的重装单据
            repeatNo = repeatMap.get(temp.getLiushBarcode());
            if (StringUtils.isEmpty(repeatNo)) {
                repeatMap.put(temp.getLiushBarcode(), temp.getZhuangcdNo());
            } else {
                if (!temp.getZhuangcdNo().equals(repeatNo)) {
                    sb.append("装车单").append(repeatNo).append("与").append(temp.getZhuangcdNo()).append("中存在重装单据，请先作废以前的单据！");
                    throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX, sb.toString());
                }
            }

            // 判断本次关联中是否存在未维护商品温度的明细
            if (temp.getWendMin() == null || temp.getWendMax() == null) {
                throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                        sb.append("未维护商品温度，请确认").toString());
            }

            temp.setCaozStaff(user.getUsername());
        }

        // 根据采集设备以及保温箱获取是否有其他关联的单据
        repeatMxList = this.psZcdMxMapper.isBindingOthZcdMx(null, cjIds, lcSns);
        // 获取所有的明细条目
        fullMxList = this.psZcdMxMapper.selectFullMxByBarcodes(liushBarcodeList);
        // 根据ID查询出来所有的设备和保温箱
        deviceList = this.deviceMapper.selectBatchIds(cjIds);
        couvenseList = this.couvenseMapper.selectBatchIds(lcSns);

        for (PsZcdMx temp : psZcdMxList) {
            temp.setCaozStaff(UserUtils.getUser().getId());
            // 判断本次关联中是否存在一个采集设备或保温箱关联了两个装车单的情况
            for (PsZcdMx compare : psZcdMxList) {
                if (!temp.getZhuangcdNo().equals(compare.getZhuangcdNo())) {
                    if (temp.getSbSn().equals(compare.getSbSn())
                            || temp.getBoxSn().equals(compare.getBoxSn())) {
                        throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                                sb.append("每台设备或者保温箱只能关联到一个装车单下").toString());
                    }
                }
                else {
                    if (temp.getBoxSn().equals(compare.getBoxSn()) &&
                            (!temp.getWendMin().equals(compare.getWendMin())
                                    || !temp.getWendMax().equals(compare.getWendMax()))) {
                        throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                                sb.append("保温箱").append(temp.getBoxSn()).append("内存在温度储存范围不同的商品").toString());
                    }
                    // 判断本次关联中是否存在一个设备关联了多个保温箱
                    if (temp.getSbSn().equals(compare.getSbSn()) &&
                            !temp.getBoxSn().equals(compare.getBoxSn())) {
                        throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                                sb.append("设备").append(temp.getSbSn()).append("关联了多个保温箱").toString());
                    }
                }
            }

            // 判断采集设备或者保温箱是否已关联了其他的单据
            if (repeatMxList != null && repeatMxList.size() > 0) {
                for (PsZcdMx compare : repeatMxList) {
                    if (!temp.getZhuangcdNo().equals(compare.getZhuangcdNo())) {
                        if (temp.getSbSn().equals(compare.getSbSn())
                                || temp.getBoxSn().equals(compare.getBoxSn())) {
                            throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                                    sb.append("每台设备或者保温箱只能关联到一个装车单下").toString());
                        }
                    }
                }
            }

            // 判断本次关联中的其他装车单明细中是否存在一个保温箱下是否存在温度范围不同的商品
            for (PsZcdMx compare : fullMxList) {
                if (temp.getBoxSn().equals(compare.getBoxSn()) &&
                        (!temp.getWendMin().equals(compare.getWendMin())
                                || !temp.getWendMax().equals(compare.getWendMax()))) {
                    throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                            sb.append("保温箱").append(temp.getBoxSn()).append("内存在温度储存范围不同的商品,请确认").toString());
                }
                // 判断本次关联中是否存在一个设备关联了多个保温箱
                if (temp.getSbSn().equals(compare.getSbSn()) &&
                        !temp.getBoxSn().equals(compare.getBoxSn())) {
                    throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX,
                            sb.append("设备").append(temp.getSbSn()).append("关联了多个保温箱").toString());
                }
            }

            // 判断本次关联中是否存在设备、保温箱与装车单的仓库不一致的情况
            for (TADevice device : deviceList) {
                if (device.getId().equals(temp.getSbSn())
                        && !device.getCangku().equals(temp.getCangku())) {
                    throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX, sb.append("设备").append(temp.getSbSn())
                            .append("与装车单").append(temp.getZhuangcdNo()).append("不属于同一个仓库！").toString());
                }
            }
            // 判断本次关联中是否存在设备、保温箱与装车单的仓库不一致的情况
            for (TACouvense couvense : couvenseList) {
                if (couvense.getId().equals(temp.getBoxSn())
                        && !couvense.getCangku().equals(temp.getCangku())) {
                    throw new BusinessAjaxException(ExceptionEnum.EXCEPTION_BUSINESS_AJAX, sb.append("保温箱").append(temp.getBoxSn())
                            .append("与装车单").append(temp.getZhuangcdNo()).append("不属于同一个仓库！").toString());
                }
            }
        }

        this.deviceMapper.clearStateByBarcodes(liushBarcodeList, WorkingStateEnum.未关联.getValue());
        this.couvenseMapper.clearStateByBarcodes(liushBarcodeList, WorkingStateEnum.未关联.getValue());

        // 更新装车单汇总的状态 1:已关联
        for (PsZcdHz temp : psZcdHzList) {
            temp.setState(PsStateEnum.已关联.getValue());
        }

        // 将装车单汇总以及明细信息保存到数据库
        this.psZcdService.updateBatchById(psZcdHzList);
        this.updateBatchById(psZcdMxList);

        // 更新采集设备和保温箱工作状态
        this.deviceMapper.updateWorkingByIds(cjIds, WorkingStateEnum.已关联.getValue());
        this.couvenseMapper.updateWorkingByIds(lcSns, WorkingStateEnum.已关联.getValue());

        // 电量预警设备关联记录
        this.electricWarningRecord(electricWarningList, psZcdMxList);

        return sb.toString();
    }

    /**
     * 记录日志
     * @param electricWarningList
     */
    private void electricWarningRecord(List<TsRelation> electricWarningList, List<PsZcdMx> zcdMxList)  {
        if (electricWarningList == null || electricWarningList.size() < 1) {
            return;
        }

        TSDeviceWarningLog log = null;
        PsZcdMx psZcdMx = null;
        Date now = new Date();
        User user = UserUtils.getUser();
        for (TsRelation tsRelation : electricWarningList) {
            for (PsZcdMx zcdMx : zcdMxList) {
                if (zcdMx.getLiushBarcode().equals(tsRelation.getLiushBarcode())) {
                    psZcdMx = zcdMx;
                    break;
                }
            }
            log = new TSDeviceWarningLog();
            log.setDeviceId(tsRelation.getCjId());
            log.setType(Log.ELECTRIC_WARNING_RELATION);
            log.setTitle(psZcdMx.getZhuangcdNo());
            log.setContent(String.valueOf(tsRelation.getElectricValue()));
            log.setCollectTime(tsRelation.getCollectTime());
            log.setCreateDate(new Timestamp(now.getTime()));
            log.setCreateBy(user);
            deviceWarningLogMapper.insert(log);
        }
    }

}
